using System.Linq.Expressions;
using WeatherSystem.API.Models;

namespace WeatherSystem.API.Specifications
{
    /// <summary>
    /// 带城市信息的天气数据查询规范
    ///
    /// 支持按城市、时间范围、数据来源等多维度查询天气数据
    /// 自动包含城市信息和活跃指标定义，按记录时间降序排列
    /// </summary>
    public class WeatherDataWithCitySpecification : BaseSpecification<WeatherDataEntry>
    {
        /// <summary>
        /// 综合查询构造函数
        /// </summary>
        /// <param name="cityId">城市ID过滤</param>
        /// <param name="startDate">开始时间</param>
        /// <param name="endDate">结束时间</param>
        /// <param name="source">数据来源过滤</param>
        public WeatherDataWithCitySpecification(Guid? cityId = null, DateTime? startDate = null, DateTime? endDate = null, string? source = null)
            : base(BuildCriteria(cityId, startDate, endDate, source))
        {
            // 包含城市信息
            AddInclude(x => x.City);
            // 包含活跃的指标值
            AddInclude(x => x.Metrics.Where(m => m.Definition != null && m.Definition.IsActive));
            // 包含指标定义信息
            AddInclude("Metrics.Definition");
            // 按记录时间降序排列
            ApplyOrderByDescending(x => x.RecordedAt);
        }

        /// <summary>
        /// 构建查询条件
        /// </summary>
        /// <param name="cityId">城市ID</param>
        /// <param name="startDate">开始时间</param>
        /// <param name="endDate">结束时间</param>
        /// <param name="source">数据来源</param>
        /// <returns>查询条件表达式</returns>
        private static Expression<Func<WeatherDataEntry, bool>>? BuildCriteria(Guid? cityId, DateTime? startDate, DateTime? endDate, string? source)
        {
            Expression<Func<WeatherDataEntry, bool>>? criteria = null;

            if (cityId.HasValue)
            {
                criteria = CombineExpressions(criteria, x => x.CityId == cityId.Value);
            }

            if (startDate.HasValue)
            {
                criteria = CombineExpressions(criteria, x => x.RecordedAt >= startDate.Value);
            }

            if (endDate.HasValue)
            {
                criteria = CombineExpressions(criteria, x => x.RecordedAt <= endDate.Value);
            }

            if (!string.IsNullOrEmpty(source))
            {
                criteria = CombineExpressions(criteria, x => x.Source == source);
            }

            return criteria;
        }

        /// <summary>
        /// 合并两个表达式
        /// </summary>
        /// <param name="first">第一个表达式</param>
        /// <param name="second">第二个表达式</param>
        /// <returns>合并后的表达式</returns>
        private static Expression<Func<WeatherDataEntry, bool>>? CombineExpressions(
            Expression<Func<WeatherDataEntry, bool>>? first,
            Expression<Func<WeatherDataEntry, bool>> second)
        {
            if (first == null) return second;

            var parameter = Expression.Parameter(typeof(WeatherDataEntry));
            var leftVisitor = new ReplaceExpressionVisitor(first.Parameters[0], parameter);
            var left = leftVisitor.Visit(first.Body);

            var rightVisitor = new ReplaceExpressionVisitor(second.Parameters[0], parameter);
            var right = rightVisitor.Visit(second.Body);

            return Expression.Lambda<Func<WeatherDataEntry, bool>>(
                Expression.AndAlso(left!, right!), parameter);
        }

        /// <summary>
        /// 表达式访问器，用于替换表达式中的参数
        /// </summary>
        private class ReplaceExpressionVisitor : ExpressionVisitor
        {
            private readonly Expression _oldValue;
            private readonly Expression _newValue;

            public ReplaceExpressionVisitor(Expression oldValue, Expression newValue)
            {
                _oldValue = oldValue;
                _newValue = newValue;
            }

            public override Expression? Visit(Expression? node)
            {
                return node == _oldValue ? _newValue : base.Visit(node);
            }
        }
    }

    /// <summary>
    /// 获取指定城市的最新天气数据规范
    ///
    /// 用于获取某个城市最近的天气数据记录，
    /// 包含完整的城市信息和指标定义
    /// </summary>
    public class LatestWeatherByCitySpecification : BaseSpecification<WeatherDataEntry>
    {
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="cityId">城市ID</param>
        public LatestWeatherByCitySpecification(Guid cityId) : base(x => x.CityId == cityId)
        {
            // 包含城市信息
            AddInclude(x => x.City);
            // 包含活跃的指标值
            AddInclude(x => x.Metrics.Where(m => m.Definition != null && m.Definition.IsActive));
            // 包含指标定义信息
            AddInclude("Metrics.Definition");
            // 按记录时间降序排列
            ApplyOrderByDescending(x => x.RecordedAt);
            // 只取第一条记录
            ApplyPaging(0, 1);
        }
    }

    /// <summary>
    /// 活跃城市查询规范
    ///
    /// 查询所有活跃状态的城市，按城市名称升序排列
    /// </summary>
    public class ActiveCitiesSpecification : BaseSpecification<City>
    {
        /// <summary>
        /// 构造函数
        /// </summary>
        public ActiveCitiesSpecification() : base(x => x.IsActive)
        {
            // 按城市名称升序排列
            ApplyOrderBy(x => x.Name);
        }
    }

    /// <summary>
    /// 统计数据查询规范
    ///
    /// 支持按城市、统计类型、时间范围查询统计数据
    /// 包含城市信息和统计值定义，按统计日期降序排列
    /// </summary>
    public class StatisticsDataSpecification : BaseSpecification<StatisticsEntry>
    {
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="cityId">城市ID</param>
        /// <param name="statisticType">统计类型（Daily、Weekly、Monthly等）</param>
        /// <param name="startDate">开始时间</param>
        /// <param name="endDate">结束时间</param>
        public StatisticsDataSpecification(Guid cityId, string? statisticType = null, DateTime? startDate = null, DateTime? endDate = null)
            : base(BuildCriteria(cityId, statisticType, startDate, endDate))
        {
            // 包含城市信息
            AddInclude(x => x.City);
            // 包含统计值
            AddInclude(x => x.Values);
            // 包含统计值定义
            AddInclude("Values.Definition");
            // 按统计日期降序排列
            ApplyOrderByDescending(x => x.StatisticDate);
        }

        /// <summary>
        /// 构建查询条件
        /// </summary>
        /// <param name="cityId">城市ID</param>
        /// <param name="statisticType">统计类型</param>
        /// <param name="startDate">开始时间</param>
        /// <param name="endDate">结束时间</param>
        /// <returns>查询条件表达式</returns>
        private static Expression<Func<StatisticsEntry, bool>> BuildCriteria(Guid cityId, string? statisticType, DateTime? startDate, DateTime? endDate)
        {
            Expression<Func<StatisticsEntry, bool>> criteria = x => x.CityId == cityId;

            if (!string.IsNullOrEmpty(statisticType))
            {
                var typeCriteria = (Expression<Func<StatisticsEntry, bool>>)(x => x.StatisticType == statisticType);
                criteria = CombineExpressions(criteria, typeCriteria);
            }

            if (startDate.HasValue)
            {
                var startCriteria = (Expression<Func<StatisticsEntry, bool>>)(x => x.StatisticDate >= startDate.Value);
                criteria = CombineExpressions(criteria, startCriteria);
            }

            if (endDate.HasValue)
            {
                var endCriteria = (Expression<Func<StatisticsEntry, bool>>)(x => x.StatisticDate <= endDate.Value);
                criteria = CombineExpressions(criteria, endCriteria);
            }

            return criteria;
        }

        /// <summary>
        /// 合并两个表达式
        /// </summary>
        /// <param name="first">第一个表达式</param>
        /// <param name="second">第二个表达式</param>
        /// <returns>合并后的表达式</returns>
        private static Expression<Func<StatisticsEntry, bool>> CombineExpressions(
            Expression<Func<StatisticsEntry, bool>> first,
            Expression<Func<StatisticsEntry, bool>> second)
        {
            var parameter = Expression.Parameter(typeof(StatisticsEntry));
            var leftVisitor = new ReplaceExpressionVisitor(first.Parameters[0], parameter);
            var left = leftVisitor.Visit(first.Body);

            var rightVisitor = new ReplaceExpressionVisitor(second.Parameters[0], parameter);
            var right = rightVisitor.Visit(second.Body);

            return Expression.Lambda<Func<StatisticsEntry, bool>>(
                Expression.AndAlso(left!, right!), parameter);
        }

        /// <summary>
        /// 表达式访问器，用于替换表达式中的参数
        /// </summary>
        private class ReplaceExpressionVisitor : ExpressionVisitor
        {
            private readonly Expression _oldValue;
            private readonly Expression _newValue;

            public ReplaceExpressionVisitor(Expression oldValue, Expression newValue)
            {
                _oldValue = oldValue;
                _newValue = newValue;
            }

            public override Expression? Visit(Expression? node)
            {
                return node == _oldValue ? _newValue : base.Visit(node);
            }
        }
    }
}